package controller;

import java.sql.SQLException;
import java.time.LocalDate;
import java.util.Collection;
import java.util.List;
import java.util.Map;

import enums.Message;
import model.Control;
import model.data.interfaces.IFinishable;
import model.data.tableModel.inventory.Inventory;
import model.data.tableModel.person.Customer;
import model.data.tableModel.person.Person;
import model.data.tableModel.person.Staff;
import model.data.tableModel.sale.Bill;
import model.data.tableModel.sale.Product;
import model.data.wrapper.InputWrapper;
import model.data.wrapper.ToPay;
import model.handler.databaseHandling.QueryFactory;
import view.GUI.mainView.KindVBox.BoxType;
import view.GUI.mainView.MainView;
import view.GUI.otherView.Login;
import view.GUI.otherView.Logout;

/**
 * Provides a Controller due to the MVC-Pattern.
 * <p>
 * Is implemented as Singleton to prevent bugs caused by multiple Controller instances.
 * 
 * @version 22.12.2014
 *
 */
public final class Controller {
	
	private Login login;
	private Logout logout;
	private MainView mainView;
	private Control control;
	
	private static Controller instance;

	/**
	 * Only constructor.
	 * <p>
	 * Is private because of the Singleton implementation.
	 */
	private Controller(){
		
		Controller.instance = this;
		control = Control.getInstance();
	}
	
	/**
	 * Returns the only instance of this class.
	 * 
	 * @param login Reference to the Login-View
	 * @return The only instance of Controller
	 */
	public static Controller getInstance(){
		if(instance == null){
			instance = new Controller();
		}
		return instance;
	}

	/**
	 * Forwards the login attempt from the view to the model in order to check.
	 * 
	 * @param nick Nick should be logged in
	 * @param password Password that was entered
	 * @param cash Cash in the cash box
	 * @param coins Number of washing tokens available
	 */
	public void tryLogin(String nick, String password, String cash, String coins) {
		control.tryLogin(nick, password, cash, coins);
	}
	
	/**
	 * Forwards the logout attempt from the view to the model in order to book the final cash and the final coins.
	 * @param cash final cash position
	 * @param coins final amount of coins
	 */
	public void tryLogout(String cash, String coins) {
		control.tryLogout(cash, coins);
	}

	/**
	 * Forwards a notification to the view that the login attempt failed.
	 * 
	 * @param msg Message that should be displayed to the user.
	 */
	public void loginFailed(Message msg) {
		login.loginFailed(msg);
	}

	/**
	 * Forwards the notification to the view that the login attempt succeeded.
	 * @param isAdmin indicates if the user is an admin or not in order to display specific admin views
	 */
	public void loginSuccess(boolean isAdmin) {
		login.loginSuccess(isAdmin);		
	}

	/**
	 * Forwards the notification to the view that the logout attempt succeeded.
	 */
	public void logOutSuccess() {
		logout.logoutSuccess();
		mainView.logoutSuccess();
	}

	/**
	 * Forwards the notification that the logout attempt failed.
	 * @param msg Reason why the attempt failed.
	 */
	public void logoutFailed(Message msg) {
		logout.logoutFailed(msg);
	}
	
	public Product getProduct(String newValue) {
		return control.getProduct(newValue);
	}
	
	public List<Product> getProducts(boolean mostUpdated,BoxType deposit) {
		return control.getProducts(mostUpdated, deposit);
	}
	
	public Collection<Customer> getActiveCustomer() {
		return control.getActiveCustomer();
	}
	
	public ToPay computeInputValue(Map<BoxType, List<InputWrapper>> inputMap) {
		return control.computeInputValue(inputMap);
	}
	
	public Customer getCustomer(String value) {
		return control.getCustomer(value);
	}
	
	public Staff getWorkingStaff() {
		return control.getWorkingStaff();
	}
	
	public boolean checkIfOldPWEquals(String value) {
		return control.checkIfOldPWEquals(value);
	}
	
	public boolean setNewPassword(Staff staff, String newPw) {
		
		return control.setNewPassword(staff, newPw);
	}
	
	public void createInvoice(String password) throws IllegalArgumentException, SQLException {
		control.createInvoice(password);
	}
	
	public void takeOrder(Map<BoxType, List<InputWrapper>> order) {
		control.takeOrder(order);
	}
	
	public List<Bill> getActiveDebts() {
		return control.getActiveDebts();
	}
	
	public boolean checkIfBillIsPaid(Customer customer) {
		
		return control.checkIfBillIsPaid(customer);
	}
	
	public List<Bill> getBills() {
		
		return QueryFactory.getHistoryBills();
	}
	
	public List<Person> getPersons() {
		return QueryFactory.getPersons();
	}
	
	public void createInventoryInvoice(List<List<InputWrapper>> inputList, Inventory inventory) {
		control.createInventoryInvoice(inputList, inventory);
	}
	
	public Collection<Staff> getStaff() {
		return control.getStaff();
	}
	
	public void deleteStaff(Staff s) {
		control.deleteStaff(s);
	}
	
	public void deleteCustomer(Customer c) {
		control.deleteCustomer(c);
	}
	
	public void addStaff(Staff s) {
		control.addStaff(s);
	}
	
	public void addProduct(Product newProduct) {
		control.addProduct(newProduct);
	}
	
	public void deleteProduct(Product replacement) {
		control.deleteProduct(replacement);
	}
	
	public void bookPurchase(ToPay toPay) {
		control.bookPurchase(toPay);
	}
	
	public Map<String, Number> getRevenueData(boolean isRevenue, List<IFinishable> selectedCustomer,LocalDate begin, LocalDate end) {
		return control.getRevenueData(isRevenue, selectedCustomer,begin,end);
	}

	public List<Product> getProductGroup(int groupID) {
		return control.getProductGroup(groupID);
	}
	
	// GETTER AND SETTER BELOW
	
	public void setMainView(MainView mainView) {
		this.mainView = mainView;
	}
	public void setLogin(Login login) {
		this.login = login;
	}
	
	public void setLogout(Logout logout){
		this.logout = logout;
	}
}
